package entity.main;

import java.io.Serializable;
import java.sql.Time;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Id;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;

import entity.general.MinTime;
import entity.general.Pair;

public class Task implements Serializable {

	@Id
	private String name;
	private MinTime timePlanned;

	private MinTime timeTakenToday = new MinTime(0,0);
	private LocalDate today;
	
	private List <Pair <LocalDate, MinTime>> timeSpentOnTask = new ArrayList<>();
	
	private String description;
	private Objective parentObjective;
	private LocalDate deadline;

	private LocalDate startDate;
	
	private static final long serialVersionUID = 1L;

	public static enum TaskType {GOAL, SINK};

	public TaskType taskType;
	
	boolean isPinned = false;
	
	boolean isCompleted = false;
	
	public static void main (String [] args)
	{
		/*
//		LocalDate dt1 = new LocalDate(1980, 10, 10);
//		LocalDate dt2 = new LocalDate(1980, 10, 10);
//		dt1.minus(dt2);
		
		Objective obj = new Objective("Objective");
//		Task t1 = new Task("Name", obj, LocalDate.now(), new LocalDate(2020, 10, 10), "Description", new Time(0,0));
//		Task t2 = new Task("Name", obj, LocalDate.now(), new LocalDate(2020, 10, 10), "Description", new Time(0,0));

		Task t1 = new Task("Name", TaskType.GOAL, obj, LocalDate.now(),  "Description", new Time(0,0));
		Task t2 = new Task("Name", TaskType.GOAL, obj, LocalDate.now(),  "Description", new Time(0,0));
		
		if(t1.equals(t2))
		{
			System.out.println("Equals");
		}
		else
		{
			System.out.println("Doesn't equal");
		}
		*/
		
//		LocalDate cur = DateTime.now().toLocalDate();
//		System.out.println(cur.getDayOfWeek());
//		cur = cur.minusDays(cur.getDayOfWeek());
//		System.out.println(cur);
		
	}
	
	public Task(String name, TaskType type, Objective parentObjective, LocalDate startDate, String description, MinTime timePlanned) {
		super();
		this.name = name;
		this.taskType = type;
		this.startDate = startDate;
		this.today = startDate;
		this.description = description;
		this.timePlanned = timePlanned;
		this.parentObjective = parentObjective;
	}   
	
	public Task(String name, TaskType type, Objective parentObjective, LocalDate startDate, LocalDate deadline, String description, MinTime timePlanned) {
		super();
		if(startDate.isAfter(deadline))
			throw new DeadlineBeforeStartDateException(startDate, deadline);

		this.name = name;
		this.taskType = type;
		this.startDate = startDate;
		this.today = startDate;
		this.description = description;
		this.timePlanned = timePlanned;
		this.deadline = deadline;
		this.parentObjective = parentObjective;
	}   
	

	public void init()
	{
		//System.out.println("Called init");
		DateTime curCalendar = new DateTime();
		LocalDate curDate = curCalendar.toLocalDate();
		
		if(curDate.isAfter(today))
		{
			if(!timeTakenToday.equals(new MinTime(0,0)))
			{
				timeSpentOnTask.add(new Pair<>(today, timeTakenToday));
				timeTakenToday = new MinTime(0,0);
			}
			today = curDate;
		}
	}

	public void setPinned(boolean ip)
	{
		isPinned = ip;
	}
	
	public boolean isPinned()
	{
		return isPinned;
	}

	public void setCompleted(boolean c)
	{
		isCompleted = c;
	}

	public boolean isCompleted()
	{
		return isCompleted;
	}
	
	public String getName() {
		return this.name;
	}

	public void setName(String Name) {
		this.name = Name;
	}   
	public MinTime getTimePlanned() {
		return this.timePlanned;
	}

	public void setTimePlanned(MinTime TimePlanned) {
		this.timePlanned = TimePlanned;
	}   
	
	public void addTimeSpent(MinTime time)
	{
		timeTakenToday = timeTakenToday.add(time);		
	}
	
	public void subTimeSpent(MinTime time) {
		if(time.equals(new MinTime(0,0)))
		{
			throw new TimeTodayAlreadyZeroException("Already zero");
		}
		timeTakenToday = timeTakenToday.sub(time);		
	}

	
	//Note that this actually returns the time spent today as well
	public List <Pair <LocalDate, MinTime>> getTimeSpentOnTask()
	{
		List <Pair <LocalDate, MinTime>> l = new ArrayList <>(timeSpentOnTask);
		
//		List <Pair <LocalDate, Time>> l = new ArrayList <>();
//		for(Pair <LocalDate, Time> p : timeSpentOnTask)
//		{
//			l.add(p);
//		}
		
		DateTime cal = new DateTime();
		LocalDate localDate = cal.toLocalDate();
//		Calendar cal = Calendar.getInstance();
		l.add(new Pair<>(localDate, timeTakenToday));
		return l;
	}
	
	public String getDescription() {
		return this.description;
	}

	public void setDescription(String Description) {
		this.description = Description;
	}   
	public Objective getParentObjective() {
		return this.parentObjective;
	}

	public void setParentObjective(Objective ParentObjective) {
		this.parentObjective = ParentObjective;
	}
	
	public LocalDate getDeadline()
	{
		return deadline;
	}
	
	public void setDeadline(LocalDate d)
	{
		deadline = d;
	}

	public LocalDate getStartDate()
	{
		return startDate;
	}
	
	public int hashCode()
	{
		return name.hashCode();
	}
	
//	public boolean equals(Object obj)
//	{
//		if(obj instanceof Task)
//		{
//			Task other = (Task)obj;
//			return other.name.equals(name) && other.description.equals(description);
//		}
//		return false;
//	}
	
	public boolean equals(Object obj)
	{
		if(obj instanceof Task)
		{
			Task other = (Task)obj;
						
//			System.out.println("Comparing " + this.toString() + " to " + other.toString());
			if(!other.name.equals(name))
			{
//				System.out.println("Failed name test");
				return false;
			}
			if(other.taskType != taskType)
			{
				return false;
			}
			if(!other.description.equals(description))
			{
//				System.out.println("Failed description test");
				return false;
			}
			if(!other.timePlanned.equals(timePlanned))
			{
//				System.out.println("Failed time planned");
				return false;
			}
			if(!parentObjective.equals(other.parentObjective))
			{
//				System.out.println("Failed parent objective");
				return false;
			}
			if(!other.startDate.equals(startDate))
			{
//				System.out.println("Failed startDate");
				return false;
			}
			if(!(deadline == null && other.deadline == null) && ((deadline == null && other.deadline != null) || (deadline != null && other.deadline == null)
					|| !other.deadline.isEqual(deadline)))
			{
//				System.out.println("Failed deadline");
//				System.out.println(deadline + ", " + other.deadline);
				return false;				
			}
			
//			if(other.deadline != deadline || (other.deadline != null && !other.deadline.equals(deadline)))

			
//			if(!other.timeTakenToday.equals(timeTakenToday))
//				return false;
//			if(!other.today.equals(today))
//				return false;

			//System.out.println("Returning true");
			return true;
		}
		//System.out.println("Returning false");
		return false;
	}
	
	public String toString()
	{
		return "(" + name + ", " + timePlanned + ", " + timeTakenToday 
				+ ", " + today + ", " + description + ", " + parentObjective 
				+ ", " + deadline + ", " + startDate + ")";
	}

	public MinTime getTimeSpentOnTaskThisWeek() {
		MinTime timeSpentThisWeek = new MinTime(0,0);
		// timeTakenToday;

		List <Pair <LocalDate, MinTime>> timeSpent = getTimeSpentOnTask();
		int at = timeSpent.size()-1; 
//		System.out.println(timeSpentOnT);
		while(at >= 0)
		{
			MinTime cTime = timeSpent.get(at).getSecond();
			LocalDate cDate = timeSpent.get(at).getFirst();
//			System.out.println("Testing " + today.toString() + " and " + cDate.toString());
			if(isWithinLastWeek(today, cDate))
			{
//				System.out.println("Time is good");
				timeSpentThisWeek = timeSpentThisWeek.add(cTime);
			}
			else
				break;
			at--;
		}
		
		return timeSpentThisWeek;
	}
	
	public float getTimeSpentThisWeekPercentage()
	{
		if(getTimePlanned().equals(new MinTime(0,0)))
		{
			return 1.0f;
		}
		else
		{
			return (float)getTimeSpentOnTaskThisWeek().getAsMinutes() / (float)getTimePlanned().getAsMinutes();
		}
	}

	private boolean isWithinLastWeek(LocalDate today, LocalDate other) {
		LocalDate endOfLastWeek = DateTime.now().toLocalDate();
		endOfLastWeek = endOfLastWeek.minusDays(endOfLastWeek.getDayOfWeek());
//		LocalDate startOfNextWeek = endOfLastWeek.plusDays(7);
		
//		if(today.minusDays(7).isAfter(other))
		if(other.isBefore(endOfLastWeek))
			return false;
		else
			return true;
	}

	public TaskType getType() {
		return taskType;
	}


}
